
package org.ccay.security.authz.aop;

import java.lang.reflect.Method;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.subject.Subject;
import org.ccay.security.annotation.SecurityOperation;
import org.ccay.security.annotation.SecurityPolicy;
import org.ccay.security.annotation.SecurityResource;
import org.ccay.security.entity.Permission;
import org.ccay.security.entity.User;
import org.ccay.security.exception.AuthenticationException;
import org.ccay.security.util.SecurityUtil;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;


public class SecurityOperationMethodInterceptor implements MethodInterceptor {
	
	protected void assertAuthorized(MethodInvocation mi)
			throws AuthorizationException {
		//实现上声明的方法
		Class<?> targetClass = mi.getThis().getClass();
		Method targetMethod = ClassUtils.getMostSpecificMethod(mi.getMethod(),targetClass);
		SecurityResource typAnnClass = AnnotationUtils.findAnnotation(targetClass, SecurityResource.class);
		SecurityOperation medAnnClass = AnnotationUtils.findAnnotation(targetMethod, SecurityOperation.class);
		if(null == typAnnClass || null == medAnnClass){
			//接口上声明的方法
			Method m = mi.getMethod();
			typAnnClass = AnnotationUtils.findAnnotation(m.getDeclaringClass(), SecurityResource.class);
			medAnnClass = AnnotationUtils.findAnnotation(m, SecurityOperation.class);
		}
		checkPermission(typAnnClass,medAnnClass);
	}
	
	protected void checkPermission(SecurityResource typAnnClass,SecurityOperation medAnnClass){
		Permission permission = new Permission(typAnnClass.code(),medAnnClass.code());
		SecurityUtil.checkPermission(permission.getPermissionString(), medAnnClass.policy());
	}
	
   protected Subject getSubject() {
        return SecurityUtils.getSubject();
    }

	@Override
	public Object invoke(MethodInvocation paramMethodInvocation) throws Throwable {
		assertAuthorized(paramMethodInvocation);
		return paramMethodInvocation.proceed();
	}
}
